package org.zn.plus.mybatis.sql.builder;

import java.util.List;
import java.util.Map;

import org.apache.ibatis.jdbc.SQL;
import org.zn.plus.mybatis.sql.builder.constant.ColumnType;
import org.zn.plus.mybatis.sql.builder.constant.Join;
import org.zn.plus.mybatis.sql.builder.constant.Operation;
import org.zn.plus.mybatis.sql.builder.model.JoinTable;
import org.zn.plus.mybatis.sql.builder.model.OnColumn;
import org.zn.plus.mybatis.sql.builder.model.QueryOrder;
import org.zn.plus.mybatis.sql.builder.model.QueryStatement;
import org.zn.plus.mybatis.sql.builder.model.QueryTable;
import org.zn.plus.mybatis.sql.builder.model.SelectColumn;
import org.zn.plus.mybatis.sql.builder.model.WhereColumn;


public class DynamicQuerySqlHandler{
	
	public String query(QueryBuilder builder) {

		return sql(builder).toString();
	}
	
	public SQL sql(QueryBuilder builder) {

		QueryStatement query= (QueryStatement) builder.buildStatement();
		
		
		Map<String, Map<String, Object>> params=builder.getParameters();
		
		SQL sql=new SQL();
		
		QueryTable tab=query.getMainTable();

		tableSql(sql, tab,params);
	
		return sql;
	}
	
	
	private void tableSql(SQL sql ,QueryTable tab,Map<String, Map<String, Object>> params) {
		
		StringBuilder sb=new StringBuilder();
		
		String tableName=sb.append(tab.getTableName()).append(" ").append(tab.getAlias()).toString(); 
		
		
		if(tab.fragmentName().equals(JoinTable.clazz)) {
			
			JoinTable jt= (JoinTable) tab;
		
			boolean s=false;
			
			sb=new StringBuilder();
			
			sb.append(" ");
			
			for (OnColumn col : jt.getOnList()) {
				
				sb.append("on").append(" ");

				if(s) {
				if(Operation.AND.equals(col.getRelation())) sb.append(" and "); 
				if(Operation.OR.equals(col.getRelation()) ) sb.append(" or ");  
				}
				
				sb.append(jt.getAlias()).append(".").append(col.getName())
				.append(col.getOpertion()).append(jt.getLinkTable().getAlias()).append(".").append(col.getLink());
					
					
			
			}
			 
			String joinTab=sb.insert(0, tableName).toString();
			
			
			if(Join.JOIN.equals(jt.getJoinType()) ) {
				
				sql.JOIN(joinTab);
				
			}else
			if(Join.LEFT.equals(jt.getJoinType()) ) {
				
				sql.LEFT_OUTER_JOIN(joinTab);
			}
			else
			if(Join.RIGHT.equals(jt.getJoinType()) ) {
					
				sql.RIGHT_OUTER_JOIN(joinTab);
			}
			else
			if(Join.OUTTER.equals(jt.getJoinType()) ) {
						
					sql.OUTER_JOIN(joinTab);
			}
					
			
		}else {
			/**
			 * 主表
			 */
			sql.FROM(tableName);

		}
		
		
		
		
		for (JoinTable join : tab.getJoinTables()) {
			
			join.setLinkTable(tab);
			
			tableSql(sql, join, params);
			
		}	
		
		
		

		for (SelectColumn col : tab.getSelectColumns()) {
			
			sb=new StringBuilder();
			
			if(ColumnType.COL.equals(col.getType()) ) {
						
			String colName=sb.append(tab.getAlias()).append(".").append(col.getName())
					.append(" ").append(col.getAlias()).toString();
			
			sql.SELECT(colName);
			
			}
			
			else if(ColumnType.SUB.equals(col.getType())) {
				
				SQL subsql =new SQL();
				tableSql(subsql, col.getSubQuery(),params);	 
				
				String subquery =subsql.toString();
				
				String sub=sb.append(" (").append(subquery).append(") ").append(col.getAlias()).toString();
				
				sql.SELECT(sub);
				
			}
			else if(ColumnType.FUNC.equals(col.getType())) {
				
			}
			
			
		} 
		
		
		/**   where 基本完成  func函数未处理  **/
		for (WhereColumn col : tab.getWhereColumns()) {
			
			sb=new StringBuilder();

			if(Operation.AND.equals(col.getRelation()) ) sql.AND();
			if(Operation.OR.equals(col.getRelation()) ) sql.OR();
			
			if(ColumnType.COL.equals(col.getType()) ) {
			
			
			sb.append(tab.getAlias()).append(".").append(col.getName())
					.append(" ").append(col.getOpertion()).append(" ");
			
			StringBuilder parmb=doParm(tab,col.getName(), params);
			
			sb.append(parmb);
			
				
			String condition=sb.toString();
			
			sql.WHERE(condition);
		
			}
			else if(ColumnType.SUB.equals(col.getType())) {
				
				SQL subsql =new SQL();
				tableSql(subsql, col.getSubQuery(),params);	 
				
				String subquery =subsql.toString();
				
				String sub=sb.append(" (").append(subquery).append(") ").append(col.getAlias()).toString();
				
				sql.WHERE(sub);
				
			}
			else if(ColumnType.FUNC.equals(col.getType())) {
				
			}
			
		
		} 
		
		
		for (QueryOrder col : tab.getOrders()) {
			
			sb=new StringBuilder();
			
			String order=sb.append(tab.getAlias()).append(".").append(col.getName()).toString();
			
			sql.ORDER_BY(order);
		}
		
		
		for (String col : tab.getGroupBys()) {
			
			sb=new StringBuilder();
			
			String groupBy=sb.append(tab.getAlias()).append(".").append(col).toString();
			
			sql.ORDER_BY(groupBy);
		}
		
	}
	
	
	
	
	
	private StringBuilder doParm(QueryTable tab,String colName,Map<String, Map<String, Object>> params ) {
		
		if(params==null)return null;
		
		StringBuilder s=new StringBuilder();
		
		Map<String, Object> map =params.get(tab.getAlias());
		
		doParmMap(tab.getAlias(),colName,s, map);
		
		return s;

	}
	
	
	private void doParmMap(String tName,String colName,StringBuilder s ,Map<String, Object> map) {
		
		String key=colName;
		Object obj=map.get(colName);
		
		if(obj instanceof String||obj instanceof Number) {
			
			s.append("#{parameters.").append(tName).append(".").append(key).append("}");
				
		}
		else if(obj instanceof List) {
			
			List<Object> l= (List<Object>) obj;
			
			s.append("(");
			
			for (int i = 0; i < l.size(); i++) {
				
				s.append("#{parameters.").append(tName).append(".").append(key)
				.append("[").append(i).append("]")
				.append("}").append(",");
				
			}
			
			s.delete(s.length()-1, s.length());
			
			s.append(")");
			
		}
	
		else if(obj instanceof Map) {
		
			doParmMap(tName+"."+key,"", s, (Map<String, Object>)obj);
		
		}	
		
		
			

		
	}
	

}
